<template>
  <div class="block">
    <el-cascader
      ref='cas'
      v-model="value"
      :options="options"
      @visible-change="visible"
      @expand-change="exchange"
      @change="handleChange"
    ></el-cascader>
    <div class="text">
      <pre>
四级联动
概念说明:
  0. 组件的选项, 每一级是一个数组, 是一个树型结构,
  [
    {value:'140000',label:'山西省',
      children:[
        {value:'141000',label:'临汾市',
          children:[
            {value:'141002',label:'尧都区',
              children:[
                {value:'141002005',label:'乡贤街街道'}
              ]
            }
          ]
        }
      ]
    }
  ]
  1. 级联组件的值, 是一个数组, 数组中的值是每级的value, 例如: [140000, 142600, 142601, 14260101].
  2. 当前激活路径, 是一个数组(只有三个值, 不包含叶子节点), 里面放了被激活的节点, 例如: [山西省, 临汾市, 尧都区], 每一个都是一个渲染出来的Dom节点
  3. expand 事件, 当要展开一个父节点时, 就会调用expand-change方法.
  3.1 通过expand-change事件, 给展开项增加子菜单
  4. visible 事件, 当要显示或隐藏菜单弹出层时, 调用visible-change方法
  4.1 通过visible-change事件, 重新根据级联的值定位菜单路径

初始状态:
  1. 没有value的状态, 一般是新增界面, 不用回显数据
    1.1 页面挂载的时候只需要初始化第一级的选项
  2. 有value的状态, 一般是编辑页面, 需要回显数据
    2.1 页面挂载的时候需要初始化每一级的数据(第一级全部的数据, 选中的第二级, 选中的第三级, 第四级数据)

操作过程:
  1. 显示弹出层, 如果value没有改变, 那么把保存的激活路径再点击一次, 如果value改变了, 那么重新保存一次激活路径
  2. 展开节点, 加载这个节点的子节点, 保存在options中.

注意:
  1. 这些方法,只有两种value改变的方式可以正确处理
    1.1 初始化value时
    1.2 手动选择选项时
    1.3 如果用代码直接操作 value值, 组件的状态可能会有异常
  2. 例子中的街道数据不完整, 只有 河北, 山西的
  3. 例子中的直辖市数据处理有问题, 暂时先不纠正了
    </pre>
    </div>
  </div>
</template>

<script>
const location = require('../utils/data_location/list.json')
// console.log(location)
export default {
  data() {
    return {
      value: ['130000', '130100', '130102', '130102001'],
      options: []
    }
  },
  created() {
    // 初始化一下数据, 把数据变成树形数据
    this.location = {
      province: [],
      city: {},
      town: {}
    }
    for (var i in location) { // 遍历, 取出code
      var p = i[0] + i[1] // 省代码2位: 如:'14'
      var c = i[2] + i[3] // 市代码2位
      var t = i[4] + i[5] // 区代码2位
      var isP = c + t === '0000' // 是否是省
      var isC = !!(!isP && t === '00') // 是否是市
      // eslint-disable-next-line no-unused-vars
      var isT = !!(!isP && !isC) // 是否是区
      if (isP) {
        // 省份
        let data = {
          value: i,
          label: location[i],
          children: []
        }
        this.location.province.push(data)
      } else if (isC) {
        // 城市
        let data = {
          value: i,
          label: location[i],
          children: []
        }
        if (this.location.city[p + '0000']) { } else { this.location.city[p + '0000'] = [] }
        this.location.city[p + '0000'].push(data)
      } else {
        let data = {
          value: i,
          label: location[i],
          children: []
        }
        if (this.location.town[p + c + '00']) { } else { this.location.town[p + c + '00'] = [] }
        this.location.town[p + c + '00'].push(data)
        // 区
      }
    }
    console.log(this.location)
    this.initLocation()
  },
  methods: {
    getTown(code) {
      // 获取街道数据
      return import('../utils/data_location/town/' + this.value[2] + '.json').then((content) => {
        console.log(content)
        let orginData = content
        let data = []
        for (let item in orginData) {
          let d = {
            value: item,
            label: orginData[item]
          }
          data.push(d)
        }
        return data
      })
    },
    initLocation() {
      // debugger
      // 初始化省份数据
      this.options = this.location.province
      console.log(this.options)
      if (this.value) {
        var the = this.options
        var value = this.value.slice(0, 3)
        for (let code of value) {
          let data = this.getLocation(code)
          the.findX([{ value: code }]).children = data
          the = data
        }
        this.getTown(this.value[2]).then((data) => {
          let the = this.options.findX([{ value: value[0] }, 'children', { value: value[1] }, 'children', { value: value[2] }])
          the.children = data
        })
      }
    },
    getLocation(code) {
      // 根据code 获取 子级 信息
      // 返回子级列表, 列表中对象需要符合options 数据的规范
      // eslint-disable-next-line no-unused-vars
      var init = !code
      // var p = code[0] + code[1] // 省代码2位: 如:'14'
      var c = code[2] + code[3] // 市代码2位
      var t = code[4] + code[5] // 区代码2位
      var isP = c + t === '0000' // 是否是省
      var isC = !!(!isP && t === '00') // 是否是市
      // var isT = !!(!isP && !isC) // 是否是区
      if (init) {
        return this.location.province
      } else if (isP) {
        return this.location.city[code]
      } else if (isC) {
        return this.location.town[code]
      }
    },
    visible(v) {
      // console.log(arguments)
      // debugger
      if (v) {
        if (this.orginValue && this.orginValue === this.value) {
          this.el.forEach(element => {
            element.click()
          })
        } else if (this.value) {
          this.orginValue = this.value
          this.el = this.$refs['cas'].panel.$el.querySelectorAll('.in-active-path')
          console.log(this.el)
        }
      }
    },
    exchange(val) {
      // val是路径, 因为是四级联动, 只有三级是路径, 一级是叶子,
      // 所以val最多是 三个元素的 列表 ['140000','141000','141002']
      console.log(val)
      // eslint-disable-next-line no-unused-vars
      let level = val.length
      let code = val[val.length - 1]
      if (level === 1) { // 展开某个省级, data是市列表
        let data = this.getLocation(code)
        this.options.findX([{ value: val[0] }]).children = data
      } else if (level === 2) { // 展开某个市, data是区列表
        let data = this.getLocation(code)
        this.options.findX([{ value: val[0] }, 'children', { value: val[1] }]).children = data
      } else { // 展开某个区, data是街道列表
        // let orginData = require('../utils/data_location/town/' + code + '.json')
        // require 会把所有的文件打包, 导致app.js 很大, 有1.2M
        // import 加载文件, 是按需动态加载
        import('../utils/data_location/town/' + code + '.json').then((content) => {
          console.log(content)
          let orginData = content
          let data = []
          for (let item in orginData) {
            let d = {
              value: item,
              label: orginData[item]
            }
            data.push(d)
          }
          let the = this.options.findX([{ value: val[0] }, 'children', { value: val[1] }, 'children', { value: val[2] }])
          the.children = data
        })
      }
    },
    handleChange(value) {
      console.log(value)
    }
  }
}
</script>
<style scoped>
.text {
  text-align: left;
}
</style>
